package com.dhcc.core.api.service.impl;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.stereotype.Service;

import com.dhcc.core.api.config.properties.JwtProperties;
import com.dhcc.core.api.service.ITokenService;
import com.dhcc.core.api.vo.TokenVo;
import com.dhcc.core.framework.cache.SysCache;
import com.dhcc.core.framework.exception.BizException;
import com.dhcc.core.framework.util.CommonUtil;
import com.dhcc.core.modules.system.entity.User;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;

/**
 * TokenService
 * @ClassName: TokenServiceImpl 
 * @Description: TODO
 * @author: cyf
 * @date: 2018年11月25日 下午7:21:55
 */
@Service
public class TokenServiceImpl implements ITokenService {
    
    @Autowired
    private JwtProperties jwtProperties;
    
    private String API_LOGOUT_TOKENS_KEY = "api_logout_tokens";
    
	@Override
    public TokenVo getToken(User user) {
        // 生成token
	    String token = generateToken(user.getId() + "", user.getLoginName(), user.getName(),
                user.getDeptId() + "", getRandomKey());
        // 生成token
	    String refreshToken = generateRefreshToken(user.getId() + "", user.getLoginName(), user.getName(),
                user.getDeptId() + "", getRandomKey());
        TokenVo vo = new TokenVo();
        vo.setToken(token);
        vo.setRefreshToken(refreshToken);
        vo.setTokenExpire(jwtProperties.getExpire());
        vo.setRefreshTokenExpire(jwtProperties.getRefreshExpire());
        vo.setTokenType(jwtProperties.getTokenType());
        return vo;
    }


	@Override
	public void logoutToken(String token, String refreshToken) {
	    Cache LogoutTokenCache = SysCache.me().dynaConfigCache(API_LOGOUT_TOKENS_KEY, jwtProperties.getRefreshExpire());
        LogoutTokenCache.putIfAbsent(token, null);
        LogoutTokenCache.putIfAbsent(refreshToken, null);
	}


    @Override
    public void verifyToken(String token,boolean isRefresh) {
        Cache LogoutTokenCache = SysCache.me().dynaConfigCache(API_LOGOUT_TOKENS_KEY, jwtProperties.getRefreshExpire());
        if(StringUtils.isBlank(token)){
            throw new BizException("token为空");
        }
        if(isTokenExpired(token)){
            throw new BizException("token已过期");
        }
        if(LogoutTokenCache.get(token) != null){
            throw new BizException("token已注销");
        }
        Boolean refresh = isRefresh(token);
        if(refresh!=isRefresh){
            if(refresh){
                throw new BizException("token为刷新Token");
            }else{
                throw new BizException("token为访问Token");
            }
        }
	}

    /**
     * 获取用户id从token中
     */
    @Override
    public Long getUserId(String token) {
        return Long.parseLong(getClaimFromToken(token).get("user_id").toString());
    }

    /**
     * 获取用户部门id从token中
     */
    @Override
    public Long getDeptId(String token) {
        return Long.parseLong(getClaimFromToken(token).get("dept_id").toString());
    }

    /**
     * 获取用户名从token中
     */
    @Override
    public String getUserName(String token) {
        return getClaimFromToken(token).getSubject();
    }

    /**
     * 获取jwt失效时间
     */
    private Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token).getExpiration();
    }

    /**
     * 是否是刷新token从token中
     */
    private Boolean isRefresh(String token) {
        return Boolean.parseBoolean(getClaimFromToken(token).get("isRefresh").toString());
    }

    /**
     * 获取jwt的payload部分
     */
    private Claims getClaimFromToken(String token) {
        return Jwts.parser().setSigningKey(jwtProperties.getSecret()).parseClaimsJws(token).getBody();
    }

    /**
     * <pre>
     *  验证token是否失效
     *  true:过期   false:没过期
     * </pre>
     */
    private Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    /**
     * 生成token(通过用户名和签名时候用的随机数)
     */
    private String generateToken(String userId, String userLoginName, String userName, String deptId, String randomKey) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(jwtProperties.getMd5Key(), randomKey);
        claims.put("user_id", userId);
        claims.put("user_login_name", userLoginName);
        claims.put("user_name", userName);
        claims.put("dept_id", deptId);
        claims.put("isRefresh", false);
        final Date createdDate = new Date();
        final Date expirationDate = new Date(createdDate.getTime() + jwtProperties.getExpire());

        return Jwts.builder().setClaims(claims).setSubject(userName).setIssuedAt(createdDate)
                .setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, jwtProperties.getSecret()).compact();
    }

    /**
     * 生成token(通过用户名和签名时候用的随机数)
     */
    private String generateRefreshToken(String userId, String userLoginName, String userName, String deptId, String randomKey) {
        Map<String, Object> claims = new HashMap<>();
        claims.put(jwtProperties.getMd5Key(), randomKey);
        claims.put("user_id", userId);
        claims.put("user_login_name", userLoginName);
        claims.put("user_name", userName);
        claims.put("dept_id", deptId);
        claims.put("isRefresh", true);
        final Date createdDate = new Date();
        final Date expirationDate = new Date(createdDate.getTime() + jwtProperties.getRefreshExpire());

        return Jwts.builder().setClaims(claims).setSubject(userName).setIssuedAt(createdDate)
                .setExpiration(expirationDate).signWith(SignatureAlgorithm.HS512, jwtProperties.getSecret()).compact();
    }

    /**
     * 获取混淆MD5签名用的随机字符串
     */
    private String getRandomKey() {
        return CommonUtil.getRandomString(6);
    }
}